﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;
using System.Windows.Forms;
using System.Threading;
using lib;
using lib.Twitter;
using Yedda;
using lib.JsonParser;

namespace one4all_UI
{
    public partial class o4aStream : Form
    {
        delegate void TwitterActionCallback(String action);
        delegate void tRefreshCallback();
        delegate void tResetBindingsCallback();


        private SListBox sb;
        private BindingList<StatusUser> blist;
        private ContextMenu listboxContextMenu;

        //Menus
        private MenuItem openLink;
        private MenuItem goToPage;
        private MenuItem copy;
        private MenuItem reply;
        private MenuItem markAsUnread;


        private TweetTextBox input;
        private Button submit;
        private Panel bottomPanel;
        private Panel topPanel;
        private Label tStats;
        private Label tUser;
        private myTwitter.myTwitter Twitter;
        private System.Windows.Forms.Timer updateTimer;




        public o4aStream(myTwitter.myTwitter t)
        {
            this.Twitter = t;
            InitializeComponent();
            InitializeAndSetupUI();
            updateListStartThread();
        }

        private void InitializeAndSetupUI()
        {
            #region initalize
            this.Shown += delegate
            {
                tUser.Text = Properties.Settings.Default.tUsername;
            };
            
            this.sb = new SListBox();
            this.openLink = new MenuItem();
            this.goToPage = new MenuItem();
            this.copy = new MenuItem();
            this.reply = new MenuItem();
            this.markAsUnread = new MenuItem();
            this.listboxContextMenu = new ContextMenu();
            this.input = new TweetTextBox();
            this.submit = new Button();
            this.bottomPanel = new Panel();
            this.topPanel = new Panel();
            this.updateTimer = new System.Windows.Forms.Timer();
            blist = new BindingList<StatusUser>();
            #endregion initialize

            #region configuration

            #region timer
            updateTimer.Interval = (55 * 1000);
            updateTimer.Start();
            updateTimer.Tick += delegate
            {
                updateListStartThread();
            };
            #endregion timer

            #region sb
            //sb - StreamItemListbox            
            sb.ItemHeight = 52;
            sb.Dock = DockStyle.Fill;
            sb.SListItemClicked += new SListItemClicked(itemClickHandler);  //Use delegate to get make right click select item. Delegates C.
            sb.ContextMenu = listboxContextMenu;
            #endregion sb

            #region topbottompanel
            //Bottom panel
            bottomPanel.Size = new Size(this.ClientSize.Width, 35);
            bottomPanel.Dock = DockStyle.Bottom;
            bottomPanel.BorderStyle = BorderStyle.FixedSingle;

            //Top panel
            topPanel.Size = new Size(this.ClientSize.Width, 20);
            topPanel.Dock = DockStyle.Top;
            topPanel.BorderStyle = BorderStyle.None;

            #endregion topbottompanel

            #region stats
            //Twitter stats
            this.tStats = new Label();
            tStats.Font = new Font(this.Font.FontFamily, 10, FontStyle.Regular);

            User minns = getMyUser();
            if (minns != null)
            {
                string scount = minns.statuses_count.ToString();
                string fers = minns.followers_count.ToString();
                string fing = minns.friends_count.ToString();
                tStats.Text = "followers(" + fers + ") friends(" + fing + ") status(" + scount + ")";
            }
            else
            {
                tStats.Text = "...";
            }
            tStats.Dock = DockStyle.Fill;
            topPanel.Controls.Add(tStats);
            #endregion stats

            #region userLabel
            //Twitter user label
            this.tUser = new Label();
            tUser.Font = new Font(this.Font.FontFamily, 10, FontStyle.Bold);
            tUser.Dock = DockStyle.Left;
            topPanel.Controls.Add(tUser);
            #endregion userLabel

            #region input
            //Input
            input.Dock = DockStyle.Fill;
            input.BorderStyle = BorderStyle.Fixed3D;
            input.TextChanged += delegate
            {
                submit.Enabled = true;
            };
            input.Leave += delegate
            {
                if (input.Text == "")
                {
                    input.StandbyMode();
                    submit.Enabled = false;
                }            
            };

            this.input.submit += delegate
            {
                updateStatus();
                sb.Select();
            };


            bottomPanel.Controls.Add(input);

            #endregion input

            #region submit
            //Submit button 
            string submitText = "Tweet!";
            submit.Text = submitText;
            submit.Size = new Size(60, bottomPanel.Height);
            submit.Dock = DockStyle.Right;
            submit.Enabled = false;
            submit.Click += delegate 
            {
                if (updateStatus())
                {
                    input.StandbyMode();
                }
            };

            bottomPanel.Controls.Add(submit);
            #endregion submit

            #region rClickMenu
            // OpenLink menuitem setup
            openLink.Name = "openLink";
            openLink.Index = 0;
            openLink.Text = "Open link";
            openLink.Click += delegate
            {
                //Todo: access the item itself.
                StatusUser item = (StatusUser)sb.SelectedItem;
                Util.OpenLinkInDefaultBrowser(Util.getFirstUrlFromText(item.status.text));                
            };


            // Open the stream item
            goToPage.Name = "goToPage";
            goToPage.Index = 1;
            goToPage.Text = "Go to Page";
            goToPage.Click += delegate
            {
                StatusUser item = (StatusUser)sb.SelectedItem;
                Util.OpenLinkInDefaultBrowser(item.user.url);
            };

            //Copy the stream item
            copy.Name = "copy";
            copy.Index = 2;
            copy.Text = "Copy Tweet";
            copy.Click += delegate
            {
                StatusUser item = (StatusUser)sb.SelectedItem;
                Clipboard.SetDataObject(item.user.name+": "+item.status.text,true);
            };

            //Reply to tweet the stream item
            markAsUnread.Name = "markAsUnread";
            markAsUnread.Index = 3;
            markAsUnread.Text = "Mark as unread";
            markAsUnread.Click += delegate{
                StatusUser item = (StatusUser)sb.SelectedItem;
                setUnreadStatus(item.status,sb.SelectedIndex);
            };

            //Reply to tweet the stream item
            reply.Name = "reply";
            reply.Index = 1;
            reply.Text = "Reply";
            reply.Click += delegate
            {
                StatusUser item = (StatusUser)sb.SelectedItem;
                input.TextEnterMode();
                this.input.Text = "@" + item.user.screen_name + " ";
                this.input.Focus();
                this.input.Select(this.input.Text.Length, 0);
            };



            //assign a contextmenustrip and add default menu items   
            MenuItem[] menus = new MenuItem[]{this.reply,this.copy};           
            listboxContextMenu.MenuItems.AddRange(menus); 
            listboxContextMenu.Popup += delegate
            {
                buildContextMenu();
            };

            #endregion rClickMenu

            #region databinding
            blist = lib.ManageStreamList.getInstance.tStatusUser;
            sb.DataSource = blist;
            #endregion databinding

            #endregion configuration

            #region addControls
            //Add controls to form
            this.Controls.Add(sb);
            this.Controls.Add(topPanel);
            this.Controls.Add(bottomPanel);
            #endregion addControls

            #region eventDelegates
            Twitter.newStatus += delegate
            {
                tResetBindings();
                tRefresh();
                Debug.WriteLine("new STATUS available");
            };
            #endregion eventDelegates

        }

        #region onLoad
        //Ensure correct location on startup
        private void o4aStream_Load(object sender, EventArgs e)
        {
            //Place the Window in correct location
            this.Left = Screen.PrimaryScreen.Bounds.Width - this.Width;
            this.Top = Screen.PrimaryScreen.WorkingArea.Height - this.Height;
        }
        #endregion onload


        #region threadedMethods

        //Refresh items
        public void tRefresh()
        {
            if (this.sb.InvokeRequired)
            {
                tRefreshCallback d = new tRefreshCallback(tRefresh);
                this.Invoke(d, new object[] { });
            }
            else
            {
                sb.DataSource = blist;
            }
        }

        //Refresh items
        public void tResetBindings()
        {
            if (this.sb.InvokeRequired)
            {
                tResetBindingsCallback d = new tResetBindingsCallback(tResetBindings);
                this.Invoke(d, new object[] { });
            }
            else
            {
                blist = lib.ManageStreamList.getInstance.tStatusUser;
                blist.ResetBindings();
            }
        }


        //Use threading to update db and redraw list
        private void updateListStartThread()
        {
            ThreadStart starter = delegate
            {
                Debug.WriteLine("Thread: Update DB started. " + DateTime.Now.ToString());
                Twitter.updateDB(getMyUser());
                Debug.WriteLine("Thread: Update DB started" + DateTime.Now.ToString());
            };
            new Thread(starter).Start();
        }


        //Use threading to update status and then redraw
        private bool updateStatus()
        {
            if ((input.Text != input.defaultText) && (input.Text != ""))
            {
                string status = input.Text;
                BackgroundWorker bg = new BackgroundWorker();
                bg.DoWork += delegate
                {
                    string str = Twitter.updateStatus(status);
                    Thread.Sleep(3000);
                    Twitter.updateDB(getMyUser());
                    tResetBindings();
                    tRefresh();

                };
                bg.RunWorkerCompleted += delegate
                {
                    submit.Enabled = false;
                };
                bg.RunWorkerAsync();
                return true;
            }
            return false;
        }

        //Use threading to set READ status 
        private void setReadStatus(Status su, int ind)
        {
            ThreadStart starter = delegate
            {
                TwitterLinq.SetStatusToRead(su);
                blist.ElementAt(ind).status.read = 1;
                Debug.WriteLine("Thread: Set status to READ for id: " + su.id);
            };
            Thread t = new Thread(starter);
            t.Start();
        }


        //Use threading to set UNREAD status 
        private void setUnreadStatus(Status su, int ind)
        {
            BackgroundWorker bg = new BackgroundWorker();
            bg.DoWork +=delegate
            {
                TwitterLinq.SetStatusToUnread(su);
                blist.ElementAt(ind).status.read = 0;
                Debug.WriteLine("Thread: Set status to UNREAD for id: " + su.id);
                blist.ResetItem(ind);
            };
            bg.RunWorkerCompleted += delegate
            {
                sb.Refresh();
            };
            bg.RunWorkerAsync();
        }
        #endregion threadedMethods

        #region itemClickHandler
        // Handler for the event SListItemClicked - Right click also selects
        private void itemClickHandler(int ind, bool right)
        {
            if (ind != -1)
            {
                if (right)
                {
                    sb.SelectedItem = sb.Items[ind];
                    StatusUser item = (StatusUser)sb.SelectedItem;
                }
                else //left click
                {
                    StatusUser item = (StatusUser)sb.SelectedItem;
                    if (item.status.read == 0)
                    {
                        setReadStatus(item.status, ind);
                        sb.Refresh();
                    }
                }
            }
            else
            {
                MessageBox.Show("Please select an item", "Context Menu Tester", MessageBoxButtons.OK, MessageBoxIcon.Asterisk);
            }
        }
        #endregion itemClickHandler

        #region menuMethods
        // contextMenu depends on item context
        private void buildContextMenu()
        {
            if (sb.Items.Count > 0)
            {
                StatusUser item = (StatusUser)sb.SelectedItem;
                bool hasUrl = (Util.getFirstUrlFromText(item.status.text) != null);
                menuAddOrRemove(hasUrl, this.openLink);
                menuAddOrRemove((item.user.url != ""), this.goToPage);
                menuAddOrRemove((item.status.read == 1), this.markAsUnread);
                this.reply.Text = "Reply to " + item.user.name;
            }
        }

        //Add or remove menuitem
        private void menuAddOrRemove(bool condToAdd, MenuItem menu)
        {
            if (condToAdd)
            {
                this.listboxContextMenu.MenuItems.Add(menu);
            }
            else
            {
                this.listboxContextMenu.MenuItems.Remove(menu);
            }
        }
        #endregion menuMethods

        #region other
        private User getMyUser()
        {
            try
            {
                string json = Twitter.getUserStatus();
                Object jsonObject = JsonParser.parseJson(json);
                List<Object> olist = JsonTwitter.jsonToTwitter(jsonObject, "Status");
                return (User)olist[0];
            }
            catch
            {
                return null;
            }

        }
        #endregion other
    }
}
